// License Notification
//======================================================
// Copyright (c) 2010 Channel Intelligence Inc.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// ======================================================




using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using CIP4.Common;

namespace CIP4.RulesEngine
{
    public class StringAtomType : AtomType
    {
        public override object AtomObjectValue
        {
            get { return AtomValue; }
        }

        public override CIP4PrimitiveType UnderlyingType
        {
            get { return CIP4PrimitiveType.CIP4String; }
        }

        /// <summary>
        /// Applicable if the AtomSource is a literal
        /// </summary>
        string m_AtomValue;

        public string AtomValue
        {
            get 
            {
                if (AtomSource == AtomSourceEnum.literal)
                    return m_AtomValue;
                else
                    return null;
            }  
            set 
            {
                if (AtomSource == AtomSourceEnum.literal)
                    m_AtomValue = value;
                else
                    throw new ArgumentException("Cannot use AtomValue unless the atom is a literal");
            }
        }

        public StringAtomType()
        {
        }

        public StringAtomType(string value)
        {
            AtomValue = value;
            AtomSource = AtomSourceEnum.literal;
        }


        public StringAtomType(AtomSourceEnum atomSource, string atomName)
            : base(atomSource, atomName)
        {
            if (AtomSource == AtomSourceEnum.literal)
                throw new ArgumentException(string.Format("A literal atom must have a value - the string parameter ({0}) to this constructor is the atom name not the literal value", atomName));
        }

        public StringAtomType(XElement element)
            : base(element)
        {
            if (element.Name != XName.Get("StringAtom", RuleXmlNS))
                throw new ArgumentException(string.Format("{0} is not a valid xml for a string atom", element.ToString()));
            if (!string.IsNullOrEmpty(element.Value))
            {
                AtomValue = element.Value;
            }
        }

        public override void XmlFor(XmlWriter xwrtr, bool writeNamespace)
        {
            xwrtr.WriteStartElement("StringAtom");
            if (writeNamespace)
                xwrtr.WriteAttributeString("xmlns", RuleXmlNS);
            base.XmlFor(xwrtr);
            if (!string.IsNullOrEmpty(AtomValue))
                xwrtr.WriteValue(AtomValue);
            xwrtr.WriteEndElement();
        }

        public override string ToString(ExpressionFormatEnum format)
        {
            if (format == ExpressionFormatEnum.javascript)
            {
                return ToJavaScriptString();
            }
            if (format == ExpressionFormatEnum.sql && AtomSource == AtomSourceEnum.literal)
            {
                object value = base.Evaluate(new RulesEngineDataPacket());
                return "'" + value.ToString().Replace("'", "''") + "'";
            }
            return ToString();
        }
        
        public override string ToString()
        {
            if (AtomSource == AtomSourceEnum.literal)
            {
                object value = base.Evaluate(new RulesEngineDataPacket());
                if (value != null)
                    return "\"" + (value.ToString()).Replace("\"", "\"\"") + "\"";
                else
                    return "nothing";
            }
            else if (AtomSource == AtomSourceEnum.namedValue)
                return AtomName;
            else if (AtomSource == AtomSourceEnum.parameter)
                return "Parameter." + AtomName;
            else if (AtomSource == AtomSourceEnum.function)
                return "Call " + AtomName + "()";
            else if (AtomSource == AtomSourceEnum.variable)
                return "Call XPath( " + AtomName + ")";
            else
                return "InvalodOp";
        }

        private string ToJavaScriptString()
        {
            switch (AtomSource)
            {
                case AtomSourceEnum.literal:
                    object value = base.Evaluate(new RulesEngineDataPacket());
                    if (value != null)
                        return "'" + value.ToString() + "'";
                    else
                        throw new InvalidExpressionException("Cannot evaluate boolean literal.");
                case AtomSourceEnum.parameter:
                    if (string.IsNullOrEmpty(AtomName))
                        throw new InvalidExpressionException("Blank atom name for boolean atom.");
                    return "parameter['" + AtomName.ToUpper() + "']";
                default:
                    throw new InvalidExpressionException("Unhandled boolean atom source: " + AtomSource);
            }
        }
    }
}
